#include <odbc++/drivermanager.h>
#include <odbc++/connection.h>
#include <odbc++/resultset.h>
#include <odbc++/resultsetmetadata.h>
#include <odbc++/preparedstatement.h>

//#include <cstdio>
#include <iostream>
#include "cidr.h"
#include <anal.h>

using namespace odbc;
using namespace std;


auto_ptr<Connection> con;

void	SQLConnect(const char *connectionInfo)
{
	cout << "Connecting to " << connectionInfo
					<< "..." << flush;
	con = auto_ptr<Connection>(DriverManager::getConnection(connectionInfo));
	cout << " done." << endl;
}


// odbc ISO YYYY-MM-DD HH24:MI:SS.FFF
//
static void timevalToDate(const struct timeval *in, char *out)
{
   struct tm *ti = localtime(&in->tv_sec);
	sprintf(out, "%04d-%02d-%02d %02d:%02d:%02d.%d", 
			ti->tm_year + 1900, ti->tm_mon + 1, ti->tm_mday,
			ti->tm_hour, ti->tm_min, ti->tm_sec,
			in->tv_usec);
}

time_t	GetRecentByDatabase()
{
	auto_ptr<PreparedStatement> pstmt = auto_ptr<PreparedStatement>(con->prepareStatement(
		"select max(last_seen) AS last_item from connections"));

	auto_ptr<ResultSet> rs = auto_ptr<ResultSet>(pstmt->executeQuery());
	if (rs->next()) {	
		rs->getRow();
		Timestamp ts = rs->getTimestamp("last_item");
		return ts.getTime();
	} else {
		cerr << "Database empty so no GetRecentByDatabase" << endl;
		exit(1);
	}
}


HostMap 	*SQLRead(const char *local_mask, int recentSeconds, char *gateway)
{
	HostMap *hm = new HostMap;
	cidr	local_cidr(local_mask, gateway);
	string	sqlSelect(
			"SELECT  "
			"  src_dns.hostname AS src_host, "
			"  src_dns.ip AS src_ip, "
			"  dst_dns.hostname AS dst_host, "
			"  dst_dns.ip as dst_ip, "
			"  connections.port_src as src_port, "
			"  connections.port_dst as dst_port, "
			"  connections.first_seen as first_seen, "
			"  connections.last_seen as last_seen, "
			"  connections.volume as volume, "
			"  connections.packets as packets "
			"FROM "
			" connections "
			" INNER JOIN dnsentry src_dns ON (connections.src_ip_serial=src_dns.serial) "
			" INNER JOIN dnsentry dst_dns ON (connections.dst_ip_serial=dst_dns.serial) "
			" WHERE last_seen > ? ");

		std::auto_ptr<PreparedStatement> pstmt = std::auto_ptr<PreparedStatement>(con->prepareStatement (sqlSelect.c_str()));

		time_t	mostRecent = 0;
		if (recentSeconds)
			mostRecent = GetRecentByDatabase() - recentSeconds;
		Timestamp ts(mostRecent);
		pstmt->setString(1, ts.toString());
		
//	pstmt->setString(1, resolvedName);


	auto_ptr<ResultSet> rs = auto_ptr<ResultSet>(pstmt->executeQuery());
	while(rs->next()) {
		rs->getRow();
		struct sockaddr_in src_ip, dst_ip;
		inet_aton(rs->getString("src_ip").c_str(), &src_ip.sin_addr);
		inet_aton(rs->getString("dst_ip").c_str(), &dst_ip.sin_addr);
		bool	isLocal = local_cidr.isLocal(src_ip.sin_addr);
		AnalConnection *ac = new AnalConnection(isLocal,
				rs->getString("src_host"), src_ip, rs->getInt("src_port"),
				rs->getString("dst_host"), dst_ip, rs->getInt("dst_port"),
				rs->getInt("packets"), rs->getLong("volume"));
		if (!isLocal && !local_cidr.isLocal(dst_ip.sin_addr)) {
//			cerr << "neither side is local - check mask " << *ac;
			delete ac;
			continue;
		}
		HostMapIter hma	= hm->find(isLocal ? src_ip.sin_addr.s_addr : dst_ip.sin_addr.s_addr);
		AnalHost *ah;
		if (hma == hm->end()) {		// not in list new record
			ah = new AnalHost;
			(*hm)[isLocal ? src_ip.sin_addr.s_addr : dst_ip.sin_addr.s_addr] = ah;
		} else {
			ah =  (*hma).second;
		}
		ah->AddConnection(ac);
	}
	return hm;
}

